package com.citywithincity.api.startup;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.citywithincity.api.AbsModule;
import com.citywithincity.api.ApiBuildUtil;
import com.citywithincity.api.ApiConfig;
import com.citywithincity.api.ApiFilter;
import com.citywithincity.api.IClassVisiter;
import com.citywithincity.api.StartupPolicy;
import com.citywithincity.db.EntityBuilder;
import com.citywithincity.interfaces.IService;
import com.citywithincity.utils.ClassUtil;
import com.citywithincity.utils.ConfigReader;
import com.citywithincity.utils.PathUtil;
import com.damai.action.Actions;
import com.damai.action.IAction;
import com.damai.action.aop.Interceptor;
import com.damai.plugins.IPlugin;
import com.jzoom.zoom.common.ConfigurationConstants;
import com.jzoom.zoom.common.filter.Filter;
import com.jzoom.zoom.common.filter.OrFilter;
import com.jzoom.zoom.common.filter.pattern.PatternFilterFactory;
import com.jzoom.zoom.common.res.ResScanner;
import com.jzoom.zoom.common.res.ResScanner.ClassRes;

import javassist.ClassPool;

/**
 * controllers 和entity
 * 
 * @author renxueliang
 *
 */
public class AutoLoadPolicy implements StartupPolicy {
	private List<IPlugin> plugins = new ArrayList<IPlugin>();
	//service最后启动
	private List<IService> services = new ArrayList<IService>();
	private static Log logger = LogFactory.getLog(ApiFilter.class);
	List<AbsModule> modules;
	List<Interceptor> interceptors = new ArrayList<Interceptor>();
	
	
	class JarFilter implements Filter<File> {

		private Filter<String> filter;

		public JarFilter(Filter<String> filter) {
			this.filter = filter;
		}

		@Override
		public boolean accept(File value) {
			return filter.accept(value.getName());
		}

	}

	@SuppressWarnings("unchecked")
	private void scanResources() {
		Filter<File> jarFilter = null;
		String jar = ConfigReader.getDefault().get("jar");
		if (!StringUtils.isEmpty(jar)) {
			jarFilter = new OrFilter<File>(ResScanner.fastFilter,
					new JarFilter(PatternFilterFactory.createFilter(jar)));
		} else {
			// 不扫描jar
			jarFilter = ResScanner.fastFilter;
		}

		try {
			ResScanner.me().scan(getClass().getClassLoader(), jarFilter);
		} catch (IOException e) {
			throw new RuntimeException("扫描解析文件出错，请确认权限是否满足要求");
		}

	}
	@Override
	public void startup(ApiConfig mainConfig, Map<String, IAction> routeMap) throws Exception {
		
		scanResources();
		
		List<String> entities = new LinkedList<String>();
		Set<String> models = new HashSet<String>();
		modules = new ArrayList<AbsModule>();
		modules.add(mainConfig);

		// 加载从config下加载
	/*	String jars = ConfigReader.getDefault().get("jar");
		if (jars != null) {
			for (String jarPath : jars.split(",")) {
				File jarFile = PathUtil.getLibJar(jarPath + ".jar");
				if (jarFile.exists()) {
					logger.info("Found jar " + jarFile.getPath() + " try load....");
					ClassUtil.appendJar(jarFile, "", "", true, classess);
				} else {
					logger.warn("Jar " + jarFile.getPath() + " not found");
				}
			}
		} else {
			logger.warn("No jars config, if this is production mode, this may course error");
		}
		
		
		String scanJars = ConfigReader.getDefault().get("scan.jar");
		*/
		
		List<ClassRes> resClass = ResScanner.me().findClass("*");
		List<String> classess = new ArrayList<String>(resClass.size());
		for (ClassRes classRes : resClass) {
			classess.add(classRes.getName());
		}
		

		long time = System.currentTimeMillis();
		List<IClassVisiter> classVisiters = new ArrayList<IClassVisiter>();
		List<String> controllerNames = new LinkedList<String>();
		for (String className : classess) {
			if (className.indexOf(".entities.") > 0) {
				entities.add(className);
			} else if (className.indexOf(".models.") > 0) {
				models.add(className);
			} else if (className.indexOf(".controllers.") > 0) {
				controllerNames.add(className);
			} else if (className.indexOf(".module.") > 0) {
				Class<?> clazz = Class.forName(className);
				if (AbsModule.class.isAssignableFrom(clazz)) {
					AbsModule module = (AbsModule) clazz.newInstance();
					modules.add(module);
					if(module instanceof IClassVisiter){
						classVisiters.add((IClassVisiter)module);
					}
				}
			}
		}
		
		
		for (AbsModule module : modules) {
			module.registerPlugins(plugins);
			module.registerIntercepters(interceptors);
			module.registerService(services);
		}
		
		
		for (IPlugin iPlugin : plugins) {
			if(iPlugin instanceof IClassVisiter){
				classVisiters.add((IClassVisiter)iPlugin);
			}
		}
		
		for (IService service : services) {
			if(service instanceof IClassVisiter){
				classVisiters.add((IClassVisiter)service);
			}
		}
		
		IClassVisiter[] visiters = classVisiters.toArray(new IClassVisiter[classVisiters.size()]);
		
		for (String className : classess) {
			for (IClassVisiter visiter : visiters) {
				visiter.onVisitClass(className);
			}
		}
		
		
		for (IPlugin iPlugin : plugins) {
			iPlugin.start();
		}


		time = System.currentTimeMillis();
		/**
		 * 绑定实体类
		 */
		for (String className : entities) {
			try {
				EntityBuilder.bindEntity(className);
			} catch (Exception e) {
				logger.error("Entity " + className + " bind error!", e);
			//	throw new RuntimeException(e);
			}
		}

		long now = System.currentTimeMillis();
		logger.info(String.format("Init entities success in %d ms!", now - time));
		time = now;

		Actions actions = new Actions(ClassPool.getDefault(), routeMap, interceptors);
		for (AbsModule module : modules) {
			module.registerActions(actions);
		}

		now = System.currentTimeMillis();
		logger.info(String.format("Init module action success in %d ms!", now - time));
		time = now;

		for (AbsModule module : modules) {
			module.beforeBindControllers();
		}

		// controller
		for (String className : controllerNames) {
			Class<?> controllerClass = Class.forName(className);
			ApiBuildUtil.helpBuildAction( ClassPool.getDefault(), controllerClass, routeMap, interceptors);
		}
		now = System.currentTimeMillis();
		logger.info(String.format("Init action success in %d ms!", now - time));
		time = now;
		
		
		for (IService service : services) {
			service.start();
		}
		
		for (AbsModule module : modules) {
			try{
				module.beforeStart();
			}catch(Throwable t){
				logger.error(t);
				if(t instanceof RuntimeException){
					throw (RuntimeException)t;
				}else{
					throw new RuntimeException(t);
				}
			}
		}
		now = System.currentTimeMillis();
		
		
		
		logger.info(String.format("Init mudules success in %d ms!", now - time));
	}

	@Override
	public void destroy() {
		if(plugins!=null){
			for (IPlugin plugin : plugins) {
				try{
					plugin.stop();
				}catch(Throwable t){
					logger.error(t);
				}
			}
			plugins.clear();
			plugins = null;
		}
		
		if(services!=null){
			for (IService service : services) {
				try{
					service.stop();
				}catch(Throwable t){
					logger.error(t);
				}
				
			}
			services.clear();
			services = null;
		}

		if (modules != null) {
			for (AbsModule iApiModule : modules) {
				try{
					iApiModule.shutDown();
				}catch(Throwable t){
					logger.error(t);
				}
			}
			modules.clear();
			modules = null;
		}
	}

	@Override
	public List<Interceptor> getInterceptors() {
		return interceptors;
	}

}
